import React, { useRef, forwardRef, useImperativeHandle, useState, useEffect, CSSProperties } from "react";
import { useEventListener } from "ahooks";
import useInfiniteScroll from "@/hooks/useInfiniteScroll";
import { Button, Image, Popover } from "antd-mobile";
import ChatBubble from "@/components/ChatBubble";
import { convertMessage } from "@/utils";
import { currentDB } from "@/index";
import { BaseInfo, ChatMessageType } from "../../../serve/interfaces";
import styles from "./MessageList.less";
import { dispatch, IStoreState } from "@/store";
import Video from "./items/Video";
import TitleLink from "./items/TitleLink";
import dayjs from 'dayjs'
import calendar from 'dayjs/plugin/calendar'
import 'dayjs/locale/zh-cn'
import { message_cancel } from "@/apis";
import { LogMessage } from "lib/interfaces";
import { Avatar } from "@/components/Avatar";
import Lines from "./items/Lines";
import Link from "./items/Link";
dayjs.extend(calendar)
dayjs.locale('zh-cn')

const Internal = (props: {
  chatroom_id: BaseInfo['_id'];
  style?: CSSProperties;
  onReply?: (item?: LogMessage<'message_send'>) => void
} & IStoreState, ref) => {
  const { chatroom_id, userMap, loginUser, style = {}, onReply } = props;
  const scrollRef = useRef<HTMLDivElement>(null);

  useEventListener(
    "wheel",
    (event) => {
      event.preventDefault();
      // 调整滚轮方向
      scrollRef?.current?.scrollBy?.(0, -event.deltaY);
    },
    { target: scrollRef }
  );

  async function requestChatContent(current: number, pageSize: number) {
    const total = await currentDB.log.where({ chatroom_id }).count();
    const list = await currentDB.log
      .where({ chatroom_id })
      .reverse()
      .offset(current * pageSize)
      .limit(pageSize)
      .toArray();

    return { total, list, current, pageSize };
  }

  const { data, mutate } = useInfiniteScroll(
    (d) => {
      const current = d ? d?.current + 1 : 0;
      return requestChatContent(current, 20);
    },
    {
      target: scrollRef,
      isNoMore: (d) => {
        if (d === undefined) {
          return true;
        }
        return d?.current * d?.pageSize > d?.total;
      },
    }
  );

  useImperativeHandle(
    ref,
    () => {
      return {
        scrollBottom() {
          if (scrollRef?.current?.scrollTop) {
            scrollRef.current.scrollTop = 0;
          }
        },
        mutate,
      };
    },
    [scrollRef]
  );

  let last_time_show = -1
  return (
    <>
      <div
        style={{
          overflow: "auto",
          ...style,
        }}
        className={styles["message-list"]}
        ref={scrollRef}
      >
        <div className={styles["message-view"]}>
          {data?.list?.sort((a, b) => b.gmt_created - a.gmt_created).map((mes, i) => {
            const last = data?.list[i + 1]
            let time_show = ''
            if (
              // 消息开始 展示时间
              !last
              // 间隔超过5分钟 展示时间
              || mes?.gmt_created - last.gmt_created > 300000
              // 连续消息超过10条 展示时间
              || i - last_time_show > 10
            ) {
              last_time_show = i
              time_show = dayjs(mes.gmt_created).calendar(null, {
                sameDay: '[今天]A h:mm',
                nextDay: '[明天]A h:mm',
                nextWeek: 'dddd A h:mm',
                lastDay: '[昨天]A h:mm',
                lastWeek: '[上]dddd A h:mm ',
                sameElse: 'YYYY/MM/DD'
              })
            }
            const created_by = mes?.created_by;
            const isCurrent = created_by === loginUser?.username;
            if (mes.type === "message_send") {
              const user = userMap?.get?.(created_by);
              return (
                <div key={mes?._id as string} className={styles["message-list-item"]}>
                  {time_show && <Notice>{time_show}<br /> &nbsp;</Notice>}
                  <ChatItem
                    avatar={user?.avatar}
                    is_master={user?.username === loginUser.username}
                    log={mes}
                    placement={isCurrent ? "left" : "right"}
                    nickname={isCurrent ? undefined : user?.name || created_by}
                    onReply={() => onReply?.(mes)}
                  />
                </div>
              );
            }
            const msg_result = convertMessage(mes as any, userMap, loginUser);
            return (
              msg_result && (
                <div key={mes?._id as string} className={styles["message-list-item"]}>
                  {time_show && <Notice>{time_show}<br /> &nbsp;</Notice>}
                  <Notice>{msg_result}</Notice>
                </div>
              )
            );
          })}
        </div>
      </div>
    </>
  );
};

export default forwardRef(Internal);

function ChatItem(props: {
  placement?: "left" | "right";
  avatar?: string;
  nickname?: string;
  log?: LogMessage<"message_send"> & BaseInfo;
  is_master: boolean;
  onReply?: () => void;
}) {
  const { log, placement, avatar, nickname } = props;
  const message = log?.message
  const flexDirection = placement === "left" ? "row-reverse" : undefined;
  let content: React.ReactNode[] = [message?.body];

  if (message?.render_items?.length) {
    content = [];
    message?.render_items.forEach((item) => {
      let node: React.ReactNode = item.body;
      switch (item.type) {
        case ChatMessageType.LINK:
          node = <Link {...item}/>;
          break;
        case ChatMessageType.FILE:
          let mat = item.body.match(/\/([^\/?]*?)(\?|$)/);
          node = (
            <a href={item.body} target="_blank">
              {mat ? mat[1] : item.body} {" "}
            </a>
          );
          break;
        case ChatMessageType.IMG:
          node = <Image src={item.body} onClick={() => dispatch((state) => ({ ...state, image: item.body }))} />;
          break;
        case ChatMessageType.VIDEO:
          node = <Video src={item.body} />;
          break;
        case ChatMessageType.LINK_WITH_TITLE:
          node = <TitleLink {...item} />;
          break;
        case ChatMessageType.TXT:
          node = <Lines body={item.body}/>
      }
      content.push(node);
    });
  }

  const [visible, setVisible] = useState(false)
  useEffect(function () {
    const hidePopover = () => setVisible(false)
    document.addEventListener('click', hidePopover)
    return function () {
      document.removeEventListener('click', hidePopover)
    }
  }, [])
  const onDoubleClick: React.MouseEventHandler<HTMLDivElement> = (e) => {
    e.preventDefault()
    setVisible(true)
  }
  const doCancel = () => {
    message_cancel({ _id: message._id || log._id })
  }
  return (
    <Popover visible={visible} content={<>
      {props.is_master ? <Button size="mini" style={{
        borderColor: 'transparent',
      }} onClick={doCancel}>撤回</Button>
        : <Button size="mini" style={{
          borderColor: 'transparent',
        }} onClick={props.onReply}>回复</Button>
      }
    </>}>
      <div
        className={styles["chat-item"]}
        style={{
          flexDirection
        }}
        onContextMenu={onDoubleClick}
        onDoubleClick={onDoubleClick}>
        <Avatar src={avatar || ""} style={{ "--size": "38.5px" }} />
        <div className={styles["chat-item-content"]}>
          {nickname && <Nickname>{nickname}</Nickname>}
          <ChatBubble
            content={
              <div style={{ wordBreak: "break-all" }}>
                {content?.map((c, i) => (
                  <React.Fragment key={i}>{c}</React.Fragment>
                ))}
              </div>
            }
            placement={placement}
            bubbleStyle={{ flexBasis: "fit-content", maxWidth: "64vw" }}
          />
        </div>
      </div>
    </Popover>
  );
}

function Notice(props) {
  return (
    <div className={styles["chat-notice"]}>
      <div>{props?.children}</div>
    </div>
  );
}

function Nickname(props) {
  return (
    <div className={styles["chat-nickname"]}>
      <div>{props?.children}</div>
    </div>
  );
}
